package cn.trigram.config;

import com.alibaba.cloud.sentinel.annotation.SentinelRestTemplate;
import com.alibaba.cloud.sentinel.rest.SentinelClientHttpResponse;
import com.alibaba.csp.sentinel.slots.block.BlockException;
import java.io.IOException;
import java.lang.reflect.Type;
import java.util.Arrays;
import org.springframework.cloud.client.loadbalancer.LoadBalanced;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.HttpInputMessage;
import org.springframework.http.HttpOutputMessage;
import org.springframework.http.HttpRequest;
import org.springframework.http.client.ClientHttpRequestExecution;
import org.springframework.http.client.ClientHttpResponse;
import org.springframework.http.converter.AbstractGenericHttpMessageConverter;
import org.springframework.http.converter.HttpMessageNotReadableException;
import org.springframework.http.converter.HttpMessageNotWritableException;
import org.springframework.web.client.DefaultResponseErrorHandler;
import org.springframework.web.client.RestTemplate;

@Configuration
public class RestTemplateLoadBalancedConfiguration {

  /**
   * LoadBalanced 注解启去Ribbon 作为负载均衡。从此这个 RestTemplate 实例只能用service-id 请求。 如果有普通请求，请创建另一个
   * RestTemplate 实例
   * <p>
   * SentinelRestTemplate 加入熔断
   */
  @SentinelRestTemplate(blockHandlerClass = ExceptionHanlder.class, blockHandler =
      "blockHandler", fallbackClass = ExceptionHanlder.class, fallback = "fallback")
  @LoadBalanced
  @Bean
  public RestTemplate restTemplate() {

    RestTemplate restTemplate = new RestTemplate();
    /*拦截器*/
    restTemplate.setInterceptors(Arrays.asList(
        (request, body, execution) -> null));
    /*错误处理*/
    restTemplate.setErrorHandler(new DefaultResponseErrorHandler() {});
    /*消息转换*/
    restTemplate.setMessageConverters(Arrays.asList(
        new AbstractGenericHttpMessageConverter<Object>() {

          @Override
          protected void writeInternal(
              Object o, Type type, HttpOutputMessage outputMessage
          ) throws IOException, HttpMessageNotWritableException {

          }

          @Override
          protected Object readInternal(
              Class<?> clazz, HttpInputMessage inputMessage
          ) throws IOException, HttpMessageNotReadableException {

            return null;
          }

          @Override
          public Object read(
              Type type, Class<?> contextClass, HttpInputMessage inputMessage
          ) throws IOException, HttpMessageNotReadableException {

            return null;
          }
        }));
    return restTemplate;
  }

  /**
   * sentinel熔断时的处理程序
   */
  public static class ExceptionHanlder {

    public static ClientHttpResponse blockHandler(
        HttpRequest request, byte[] body, ClientHttpRequestExecution execution,
        BlockException exception
    ) {

      String s = request.getURI() + "被熔断降级";
      return new SentinelClientHttpResponse(s);
    }

    public static ClientHttpResponse fallback(
        HttpRequest request, byte[] body, ClientHttpRequestExecution execution,
        BlockException exception
    ) {

      String s = request.getURI() + "被流控限流";
      return new SentinelClientHttpResponse(s);
    }

  }

}
